#include <mutex>
#include <opencv2/opencv.hpp>

#include "video.h"

std::queue<MatWrapper> img_queue; // 图像队列
std::mutex queue_mutex;          // 队列互斥锁
std::condition_variable pic_cond;     // 条件变量

std::queue<VideoMuxPacket> g_video_mux_packet_queue[4]; // 视频队列
//std::queue<AVPacket*> g_video_mux_packet_queue[4]; // 视频队列
std::mutex g_video_mux_packet_queue_mutex[4];          // 队列互斥锁
std::condition_variable g_video_mux_packet_queue_cv[4];     // 条件变量

//void VideoStreamThread::save_start()
//{
//	m_need_save = true;
//}
//
//void VideoStreamThread::save_stop()
//{
//	m_need_save = false;
//}

void VideoStreamThread::video_mux_start()
{
	m_video_mux_stop = false;
}

void VideoStreamThread::video_mux_stop()
{
	m_video_mux_stop = true;
}

void VideoStreamThread::run() {
	std::string video_url = m_url;
	AVFormatContext *pFormatCtx = NULL;
	AVDictionary *options = NULL;
	AVPacket *av_packet = NULL; // AVPacket暂存解码之前的媒体数据
	AVFrame *av_frame = NULL;	// AVFrame暂存解码之后的媒体数据
	AVCodecParameters *av_codec_param = NULL;
	AVCodec *av_codec = NULL;			 // 解码器的种类
	AVCodecContext *av_codec_ctx = NULL; // 解码器上下文
	SwsContext *sws_ctx = NULL; // 视频数据转换上下文
	AVFormatContext *out_pFormatCtx = NULL; // 输出流上下文
	AVStream *out_stream = NULL;		 // 输出流
    int ret = -1;

    QElapsedTimer fpsTimer;
    int fpsCount = 0;
    double currentFps = 0.0;

    fpsTimer.start();

    m_stop = false;

	avformat_network_init();

	av_dict_set(&options, "buffer_size", "4096000", 0); // 设置缓存大小
	av_dict_set(&options, "rtsp_transport", "tcp", 0);	// 以tcp的方式打开,
	av_dict_set(&options, "stimeout", "5000000", 0);	// 设置超时断开链接时间，单位us,   5s
	av_dict_set(&options, "max_delay", "500000", 0);	// 设置最大时延

	pFormatCtx = avformat_alloc_context();

	if (avformat_open_input(&pFormatCtx, video_url.c_str(), NULL, &options) != 0) {
		std::cout << "Couldn't open input stream.\n"
				  << std::endl;
		return;
	}

	// 获取视频文件信息
	if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
		std::cout << "Couldn't find stream information." << std::endl;
		return;
	}

	// 查找码流中是否有视频流
	int videoindex = -1;
	unsigned i = 0;
	for (i = 0; i < pFormatCtx->nb_streams; i++) {
		if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
			videoindex = i;
			break;
		}
	}
	if (videoindex == -1) {

		std::cout << "Didn't find a video stream.\n"
				  << std::endl;

		return;
	}

	av_packet = (AVPacket *)av_malloc(sizeof(AVPacket));

	av_codec_param = pFormatCtx->streams[videoindex]->codecpar;
	av_codec = (AVCodec *)avcodec_find_decoder(av_codec_param->codec_id);
	if (av_codec) {
		printf("Video Stream Codec Name: %s\n", av_codec->name);
		printf("Video Stream Codec Long Name: %s\n", av_codec->long_name);
	} else {
		printf("Unsupported video codec ID: %d\n", av_codec_param->codec_id);
	}

	// 初始化解码器上下文
	av_codec_ctx = avcodec_alloc_context3(av_codec);
    // 这里是在将解码器参数复制到解码器上下文
	if (avcodec_parameters_to_context(av_codec_ctx, av_codec_param) < 0) {
		printf("Couldn't copy codec context\n");
		return;
	}
	// 打开解码器
	if (avcodec_open2(av_codec_ctx, av_codec, NULL) < 0) {
		printf("Couldn't open codec\n");
		return;
	}

	av_frame = av_frame_alloc();
	AVFrame *rgb_frame = av_frame_alloc(); // 用于存放解转换之后的RGB数据
	ret = av_image_alloc(rgb_frame->data, rgb_frame->linesize, av_codec_ctx->width, av_codec_ctx->height, AV_PIX_FMT_RGB24, 1);
	if (ret < 0) {
		// 错误处理
		fprintf(stderr, "Could not allocate raw picture buffer\n");
		return;
	}

	// 创建视频数据转换上下文
	sws_ctx = sws_getContext(
		av_codec_ctx->width, av_codec_ctx->height, av_codec_ctx->pix_fmt,
		av_codec_ctx->width, av_codec_ctx->height, AV_PIX_FMT_RGB24,
		SWS_BILINEAR, nullptr, nullptr, nullptr);

	// cv::Mat rgb_mat;
	cv::Mat rgb_mat(av_codec_ctx->height, av_codec_ctx->width, CV_8UC3, rgb_frame->data[0]);

	while (!m_stop) {
		if (av_read_frame(pFormatCtx, av_packet) >= 0) {
			if (av_packet->stream_index == videoindex) {
				// 这里就是接收到的未解码之前的数据
				// std::cout << "\ndata size is:" << av_packet->size;
				// 如果有必要，写一个将解码之前的h264格式的数据流保存的逻辑
				if (!m_video_mux_stop)
				{
                    // INFO: freed at the consumer side?
                    // TODO: empty all queues when exiting
                    AVPacket* video_packet = av_packet_clone(av_packet);
					{
						//std::cout << "video_pts = " << video_packet->pts << std::endl;
						std::lock_guard<std::mutex> lock(g_video_mux_packet_queue_mutex[m_id]);

						video_packet->time_base = pFormatCtx->streams[videoindex]->time_base;
						if (video_pts == -1 && video_packet->pts < 0)
						{
							video_pts = 0;
							video_packet->pts = 0;
							video_packet->dts = 0;
						}
						else if (video_pts == -1 && video_packet->pts >= 0)
						{
							video_pts = video_packet->pts;
							video_packet->pts -= video_pts;
							video_packet->dts = video_packet->pts;
						}
						else
						{
							video_packet->pts -= video_pts;
							video_packet->dts = video_packet->pts;
						}
						VideoMuxPacket video_mux_packet = { video_packet, av_codec_param };
						g_video_mux_packet_queue[m_id].push(video_mux_packet);
					}
					g_video_mux_packet_queue_cv[m_id].notify_one();
				}
				else
				{
					// 重置时间戳
					video_pts = -1;
				}

				int ret = avcodec_send_packet(av_codec_ctx, av_packet);
				if (ret < 0) {
					std::cerr << "Error sending a packet for decoding" << std::endl;
					break;
				}

				while (ret >= 0) {
					ret = avcodec_receive_frame(av_codec_ctx, av_frame);
					if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                        break;
                    } else if (ret < 0) {
						std::cerr << "Error during decoding" << std::endl;
						break;
					}

					// 将解码后的 YUV 帧转换为 RGB
					sws_scale(sws_ctx, av_frame->data, av_frame->linesize, 0, av_codec_ctx->height, rgb_frame->data, rgb_frame->linesize);

					// 将获得的 RGB 数据深拷贝到 OpenCV 的 Mat 对象中
					rgb_mat = cv::Mat(av_codec_ctx->height, av_codec_ctx->width, CV_8UC3, rgb_frame->data[0]).clone();
					cv::Mat bgr_mat;
					cv::cvtColor(rgb_mat, bgr_mat, cv::COLOR_BGR2RGB);
					MatWrapper rgb_mat_wrapper = MatWrapper{bgr_mat, m_id};
					{
						std::unique_lock<std::mutex> lock(queue_mutex);
                        img_queue.push(rgb_mat_wrapper);
					}  // 离开作用域，lock 自动销毁并解锁
					pic_cond.notify_one();
				}
				av_frame_unref(av_frame);
			}
			if (av_packet != NULL)
				av_packet_unref(av_packet);
            ++fpsCount;
            // 每秒计算一次
            if (fpsTimer.elapsed() >= 1000) {
                currentFps = static_cast<double>(fpsCount) / (fpsTimer.elapsed() / 1000.0);
                qDebug() << "cam_id: " << m_id << ", Current fps:" << currentFps;

                // 重置计时器和计数器
                fpsTimer.restart();
                fpsCount = 0;
            }
		}
	}

    if (av_codec_ctx) {
        avcodec_free_context(&av_codec_ctx);
    }
    if (sws_ctx) {
        sws_freeContext(sws_ctx);
    }
    if (rgb_frame) {
        av_freep(&rgb_frame->data[0]);
        av_frame_free(&rgb_frame);
    }
    av_frame_free(&av_frame);

    // INFO: send black image
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        img_queue.push({rgb_mat.setTo(cv::Scalar(0, 0, 0)), m_id});
    }

	av_free(av_packet);
	avformat_close_input(&pFormatCtx);
	return;
}
